package chapter

import scala.collection._
import scala.collection.mutable.LinkedHashSet
import scala.collection.immutable.HashMap
import scala.collection.mutable.ListBuffer

object Chapter13 extends App {

  //1 "Mississippi" => M ->{0} i -> {1,4,7,10} ..
  def indexs(str: String): Map[Char, Iterable[Int]] = {
    val rsMap = mutable.LinkedHashMap[Char, LinkedHashSet[Int]]()
    str.zipWithIndex foreach { case (ckey, index) => rsMap += ckey -> (rsMap.getOrElse(ckey, LinkedHashSet.empty) += index) }
    rsMap
  }
  val result1 = Map('M' -> Set(0), 'i' -> Set(1, 4, 7, 10), 's' -> Set(2, 3, 5, 6), 'p' -> Set(8, 9))
  assert(indexs("Mississippi") == result1)

  /*  def indexs2(str: String) =
    str.zipWithIndex.toList.groupBy(_._1).map { case (k, v) => (k -> v.map(_._2).toList) }
  //result2:Map('M' -> List(0), 's' -> List(2, 3, 5, 6), 'p' -> List(8, 9), 'i' -> List(1, 4, 7, 10))
*/
  //2 
  def indexs2(str: String) = {
    var rsMap = new HashMap[Char, ListBuffer[Int]]()
    str.zipWithIndex foreach { case (ckey, index) => rsMap += ckey -> (rsMap.getOrElse(ckey, ListBuffer.empty) += index) }
    rsMap
  }
  //result2:Map('M' -> List(0), 's' -> List(2, 3, 5, 6), 'p' -> List(8, 9), 'i' -> List(1, 4, 7, 10))

  def indexs3(str: String) = (Map[Char, List[Int]]() /: str.zipWithIndex) {
    (m, c) => m + (c._1 -> (m.getOrElse(c._1, List.empty[Int]) :+ c._2))
  }
  println("indexs3Result="+indexs3("Mississippi"))

  //3  List().filter(_ != 0)     
  def filterZero(numList: List[Int]) = {
    def loop(outList: List[Int], inList: List[Int]): List[Int] = inList match {
      case Nil => outList
      case head :: tails if (head == 0) => loop(outList, tails)
      case head :: tails => loop(head :: outList, tails)
    }
    loop(List.empty[Int], numList)
  }
  println(filterZero(List(0, 3, 2, 5, 6, 0, 8)))

  //4 flatMap get Option
  def function4(strList: Iterable[String], str2IntMap: Map[String, Int]): Iterable[Int] =
    strList.flatMap(str2IntMap.get(_))
  val a = Array("Tom", "Fred", "Harry")
  val m = Map("Tom" -> 3, "Dick" -> 4, "Harry" -> 5)
  println(function4(a, m).mkString(","))

  //5 mkString
  def function5[T](list: Iterable[T], step: String = "") = list.map(_.toString) reduceLeft (_.toString + step + _.toString)

  println(function5(List(1, 2, 3, 4, 5), "-"))

  //6
  val lst = List(1, 2, 3, 4, 5)
  val lstFoldLeft = (lst :\ List[Int]())(_ :: _) // foldLeft  List(1, 2, 3, 4, 5)
  val listFoldRight = (List[Int]() /: lst)(_ :+ _) // foldRight List(1, 2, 3, 4, 5)
  val lstReverse = (List[Int]() /: lst)((x, y) => y :: x) // List(5, 4, 3, 2, 1)

  //7
  val prices = List(5.0, 20.0, 9.95)
  val quantities = List(10, 2, 1)

  val sum = (prices, quantities).zipped map { _ * _ }
  val sum2 = (prices zip quantities) map (Function.tupled(_ * _))
  //8
  def function8(arys: Iterable[Double], step: Int = 3) = arys.grouped(step).toArray.map(_.toArray)
  //9

  //10
  val str = "sdfkcxpaerjoiewqjvwenfosdcwqwpeoqjrijrvnlsdkndvkjlspqwejieonsjdfksdfsdfqweioruu"
  val frequencies = str.par.aggregate(new collection.immutable.HashMap[Char, Int])(
    (x, c) => x + (c -> (x.getOrElse(c, 0) + 1)), (map1, map2) => map2 ++ map1.map { case (k, v) => k -> (v + map2.getOrElse(k, 0)) })
  println(frequencies)

}